home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 48
/
Amiga Format CD48 (1999-12-13)(Future Publishing)(GB)(Track 1 of 2)[!][issue 2000-01].iso
/
-in_the_mag-
/
networking
/
crosspc
/
parpc04
/
packet
/
src
/
parnet.asm
< prev
next >
Wrap
Assembly Source File
|
1993-09-01
|
15KB
|
493 lines
version equ 1
include defs.asm ;SEE ENCLOSED COPYRIGHT MESSAGE
; PARnet PC/FTP Packet Driver Source, conforming to version 1.08 of spec.
; Ported by S.A.Pechler (S.A.Pechler@bdk.tue.nl) from the Amiga's PARnet
; device.
; Original Amiga code is Copyright (c) 1989 by Matthew Dillon.
;
; Date: July 10, 1993
; Permission is granted to any individual or institution to use,copy,
; modify or redistribute this software provided this notice is retained.
; The authors make no guarantee to the suitability of the software for
; any purpose. Any damage caused by using this program is the responsibility
; of the user and not the authors.
code segment word public
assume cs:code, ds:code
; PARnet definitions
BUFSIZE EQU 4096
PARPORT EQU 4 ; This is 1024 in 2 byte network order (0400h)
TX_HDRSIZE EQU 8
ARP_TYPE EQU 0608h ; ARP packet type identifier in host order
; Private Data
; ------------
; Driver definitions
ether_arp_frame db 0,0,0,0,0
arp_srcaddr db ? ; target ethernet address (myself)
db 0,0,0,0,0,0 ; source ethernet address (fake)
ether_arp_type db 8,6 ; type field (0806h)
db 0,1 ; hardware type (1 = ethernet)
db 8,0 ; protocol type ( 0800h = IP addresses)
db 6 ; hardware address length (6 for ethernet)
db 4 ; address length for high level (4 for IP addr)
db 0,2 ; operation: response
arp_sendhard db 0,0,0,0,0,? ; sender hardware address
arp_sendIP db 0,0,0,0 ; sender IP address
arp_targhard db 0,0,0,0,0,? ; target hardware address (myself)
arp_targIP db 0,0,0,0 ; target IP address (myself)
ether_arp_end label byte
ARP_LENGTH EQU ether_arp_end-ether_arp_frame
; Receiver buffer (contains PARnet packet header)
rx_buffer db BUFSIZE dup(?) ; receiver buffer (max 64 kb).
rx_header EQU rx_buffer
rx_port EQU rx_buffer ; ! port number is in network order.
rx_dlen EQU rx_buffer+6 ; ! last 2 bytes of length (is in network
; ! order!).
rx_data EQU rx_buffer+8
; pointer to receiver buffer (given to upper level process).
;rx_offset dw rx_data ; buffer data offset
; transmitter packet header
tx_header dw PARport ; portnumber is fixed to 1024 (in network order)
dw 0 ; checksum
dw 0 ; length of datafield; it should be a DD
tx_dlen EQU this word
tx_dlenh db 0 ; but on PC's a PARnet packet can't be
tx_dlenl db 0 ; larger than 64 kb.
; pointer to transmitter buffer
tx_data EQU this dword
tx_offset dw ? ; offset of host transmit buffer
tx_segment dw ? ; segment of host transmit buffer
tx_length dw ? ; packet length
tx_dest db ? ; physical destination address
output_active db 0 ; flag, packet being written.
; Public Data
; -----------
public int_no,io_addr,mem_base
int_no db 2,0,0,0 ;must be four bytes long for get_number.
io_addr dw 0378h,0 ;io addr for parallel card (default)
mem_base dw 0,0 ;share memory addr (not used)
public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db 1,0,0,0 ;no class specified for PARnet,
;using class for serial line (the
;trailing zero's are for the
;print_number function
driver_type db 0,0,0,0 ;no specific type.
driver_name db 'PARnet',0 ;name of the driver.
driver_function db 2 ;basic and extended functions present.
parameter_list label byte
db 1 ;major rev of packet driver
db 9 ;minor rev of packet driver
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
int_num dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,
public rcv_modes
rcv_modes dw 7 ;number of receive modes in our table.
dw 0,0,rcv_mode_2,0,0,0,rcv_mode_6
; Private routines
; ----------------
; See PARKERN.ASM
include parsubr.asm
; Public routines
; ---------------
public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret
public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret
public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret
public send_pkt
send_pkt:
;enter with es:di->upcall routine, (0:0) if no upcall is desired.
; (only if the high-performance bit is set in driver_function)
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
assume ds:nothing
;a PARnet network can't handle broadcasts, but ARP-requests will be
;'answerred' by making an ARP-response with as hardware address the
;LSB of the destination IP-address.
mov al,[si+EADDR_LEN-1] ; get LSB of destination hard.address
cmp al,-1 ; is it 0xff?
jne send_pkt_nobrd ; no, just send the packet
mov ax,[si+EADDR_LEN+EADDR_LEN] ; get packet type
cmp ax,ARP_TYPE ; is it an ARP-packet?
jne send_pkt_err ; no, can't handle this packet
; no need to save es:di here ?
; swap sender & targer address fields:
; 1. put sender addresses into target address fields
add si,22 ; let SI point to sender's hardware address
mov cx,EADDR_LEN+4 ; copy both the hardware & IP addresses
mov ax,cs
mov es,ax ; mov es,cs ; is this needed?
mov di,OFFSET arp_targhard
rep movsb
; 2. put target IP address into sender IP address field
add si,EADDR_LEN ; skip target hardware address
mov cx,4 ; IP address length
mov di,OFFSET arp_sendIP
rep movsb
; now calculate the target hardware address from the last octet of
; the IP address.
mov al,[si-1]
mov arp_sendhard+5,al
; prepare arp response for the receiver
mov ax,cs ; ds=cs align
mov ds,ax
assume ds:code
mov es,ax ; for es:di pointer
mov di,offset ether_arp_type ; pointer to type field
mov si,offset ether_arp_frame ; pointer to start of frame
mov cx,ARP_LENGTH ; packet length
jmp recv_reply_arp ; Pass the arp response to the receiver
send_pkt_nobrd:
assume ds:nothing
mov tx_segment,ds ; tx->data
mov bx,cs ; cs = ds align
mov ds,bx
assume ds:code
mov tx_dest,al ; hardware destination address.
mov tx_offset,si ; tx_offset ->segment offset
mov tx_length,cx ; packet data length (host order)
;Create a PARnet packet header
;(At the moment it's simple: just fill in the data-length, the rest
; is default)
mov tx_dlenh,ch ; put it in network order
mov tx_dlenl,cl
;Send the packet
mov output_active,1 ; set flag, to undo recv-interrupt
call ParWrite ; see parsubr.asm
mov output_active,0 ; recv-intrps are now accepted again
or ax,ax ; check return value (# bytes written)
jz send_pkt_err ; = 0, can't..
js send_pkt_err ; < 0, error.
cmp tx_length,ax ; check if all bytes were written
jne send_pkt_err ; not, then error.
clc
jmp short send_pkt_end
send_pkt_err:
mov dh,CANT_SEND ; errornum
stc
send_pkt_end:
ret
public get_address
get_address:
;get the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
assume ds:code
cmp cx, EADDR_LEN ; does caller want reasonable length?
jb get_addr_fail ; no , fails
cld ; make sure of string operation
mov si,offset Par_EthAddr ; load source of address
mov cx,EADDR_LEN ; return length of address
rep movsb ; copy address
mov cx,EADDR_LEN ; return length of address
clc
ret
get_addr_fail:
stc
ret
public set_address
set_address:
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
assume ds:nothing
cmp cx,EADDR_LEN ; check if address ok
je set_addr_1
mov dh,BAD_ADDRESS ; don't like length
stc
ret
set_addr_1:
; is ES always pointing to CS at this moment?
mov di,offset Par_EthAddr ;di->destination offset
rep movsb ;return address
mov cx,EADDR_LEN ;return their address length.
clc
ret
rcv_mode_2:
; Turn off receiver
ret
rcv_mode_6:
; Receive all packets (Promiscuous physical plus all multi)
ret
public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, cx = number of addresses.
;return nc if we set all of them, or cy,dh=error if we didn't.
mov dh,NO_MULTICAST
stc
ret
public terminate
terminate:
ret
public reset_interface
reset_interface:
;reset the interface.
assume ds:code
call stable
ret
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type, dl = packet class.
extrn recv_find: near
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
extrn recv_copy: near
extrn count_in_err: near
extrn count_out_err: near
public recv
recv:
;called from the recv isr. All registers have been saved, and ds=cs.
; all interrupts come here
;Upon exit, the interrupt will be acknowledged.
assume ds:code
;sti
cld
; an IRQ 7 occures only when an incoming packet is pending.
; so check with ParDataReady if the packet is addressed to me.
; otherwise quit.
; (is buffering needed?)
recv1:
cmp output_active,1
je Not_for_me ; 1 = interrupt during write
call pardataready
or al,al
jz Line_idle ; AL = 0, nothing on the line anymore
js Not_for_me ; AL = -1, packet not addressed to me
call parread
or ax,ax
jz Read_error ; AL = 0, no bytes read
js Read_error ; AL = -1, read timeout
cmp ax,BUFSIZE
jg Read_overflow ; packet did not fit in buffer.
; push packet to upper layer.
mov ch,rx_dlen ; convert packet length
mov cl,rx_dlen+1 ; to byte order.
mov ax,cs
mov es,ax ; for es:di pointer in recv_find call
mov di,offset rx_data ; reset di to beginning
mov si,di ; si will be used later
add di,EADDR_LEN+EADDR_LEN ; point to type field
; of buffer
recv_reply_arp:
mov dl, BLUEBOOK ;packet class: assume bluebook Ethernet
push cx ; save packet_length
push si ; save packet start
call recv_find ; loop up our type (first call).
pop si
pop cx
mov ax,es ; ax->es
or ax,di ; is this pointer null? (es=di=0)
je rcv_no_copy
push cx ; save packet length
push es ; remember client's buffer
push di
rep movsb ; copy from SI (packet start) to
; DI (upper level buffer)
pop si ; make client's buffer a new source
pop ds ; for the recv_copy call.
pop cx
call recv_copy ; second call
rcv_no_copy:
Line_Idle:
Not_for_me:
Read_error:
Read_overflow:
mov ax,cs ; set DS back to CS, otherwise the
mov ds,ax ; remaining ISR routine will crash.
assume ds:code
ret
public recv_exiting
recv_exiting:
;called from the recv isr after interrupts have been acknowledged.
;Only ds and ax have been saved.
assume ds:nothing
ret
;any code after this will not be kept after initialization.
end_resident label byte
public usage_msg
usage_msg db "usage: PARNET [-n] [-d] [-w] <packet_int_no> <int_level> <io_addr> <netaddr>",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet Driver for PARnet, version "
db '0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db "Ported by S.A.Pechler@bdk.tue.nl. "
db "Portions Copyright 1989, Matthew Dillon.",CR,LF,'$'
int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
PARaddress_name db "PARnet address ",'$'
bad_addr_msg db "Bad PARnet address given.",CR,LF,'$'
extrn set_recv_isr: near
;enter with si -> argument string, di -> word to store.
;if there is no number, don't change the number.
extrn get_number: near
;enter with dx -> name of word, di -> dword to print.
extrn print_number: near
extrn error: near
public parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
mov di,offset int_no
call get_number
jc param_error
mov di,offset io_addr
call get_number
jc param_error
mov di,offset parnetaddr
call get_number
jc param_error
; call print_parameters
mov al,parnetaddr
or al,al ; address 0 is reserved
je parnet_err
cmp al,-1 ; address 255 is reserved
je parnet_err
mov arp_srcaddr,al ; initialize the arp response packet
clc
ret
param_error:
mov dx,offset usage_msg
jmp error
parnet_err:
mov dx,offset bad_addr_msg
jmp error
public etopen
etopen:
call paraddress
call set_recv_isr ;install the interrupt handler
mov dx,offset end_resident
clc
ret
public print_parameters
print_parameters:
mov di,offset int_no
mov dx,offset int_no_name
call print_number
mov di,offset io_addr
mov dx,offset io_addr_name
call print_number
mov di,offset parnetaddr
mov dx,offset PARaddress_name
call print_number
ret
code ends
end